// ==UserScript==
// @name         增强版网页请求监听器
// @namespace    http://tampermonkey.net/
// @version      0.2
// @description  监听特定URL的请求并执行自定义操作
// @author       Your Name
// @match        https://www.doubao.com/*
// @grant        GM_notification
// @grant        GM_log
// ==/UserScript==

(function () {
  "use strict";

  // 请求参数
  // var reqParams = {};

  // --------------------------
  // 监听配置 -- 监听数据API请求
  // --------------------------
  const config = {
    // 需要监听的URL规则列表
    watchRules: [
      {
        // URL包含此字符串的请求会被监听
        urlContains: "/artifact/search",
        // 匹配时执行的操作
        onMatch: function (requestInfo) {
          if (
            typeof requestInfo.response === "object" &&
            requestInfo.response !== null &&
            requestInfo.response.code === 0
          ) {
            console.log("[监听器] 匹配到数据API请求，请求成功:", requestInfo);
            // 保存artifacts信息到localStorage
            saveArtifactsToLocalStorage(requestInfo.response.data);
          } else {
            console.log("[监听器] 匹配到数据API请求，请求失败:", requestInfo);
          }
        },
      },
      {
        // URL包含此字符串的请求会被监听
        urlContains: "/setting/get",
        // 匹配时执行的操作
        onMatch: function (requestInfo) {
          console.log("[监听器] 匹配到setting/get请求:", requestInfo);
          // 获取URL参数
          // 获取到的url并不完整
          const url = new URL(requestInfo.url, window.location.href);
          const params = url.searchParams;

          // 将URL参数转换为对象，过滤掉msToken和a_bogus参数
          const urlParams = {};
          for (const [key, value] of params.entries()) {
            // 跳过msToken和a_bogus参数
            if (key !== "msToken" && key !== "a_bogus") {
              urlParams[key] = value;
            }
          }
          console.log("[监听器] setting/get请求的URL参数:", urlParams);
          // reqParams = urlParams;
          getResourceDownloadUrl(urlParams);
        },
      },
    ],

    // 是否在控制台显示所有请求（即使不匹配规则）
    logAllRequests: false,
  };

  // --------------------------
  // 工具函数
  // --------------------------

  /**
   * 检查URL是否匹配任何规则
   */
  function checkUrlMatchesRules(url) {
    return config.watchRules.filter((rule) => url.includes(rule.urlContains));
  }

  /**
   * 处理请求信息并执行匹配的规则
   */
  function processRequest(requestInfo) {
    // 检查是否匹配任何规则
    const matchingRules = checkUrlMatchesRules(requestInfo.url);

    // 执行所有匹配规则的操作
    matchingRules.forEach((rule) => {
      try {
        rule.onMatch(requestInfo);
      } catch (error) {
        console.error(`[监听器] 执行规则时出错:`, error);
      }
    });

    // 如果配置了记录所有请求，则在控制台显示
    if (config.logAllRequests || matchingRules.length > 0) {
      console.log(`[监听器] ${requestInfo.type} 请求:`, requestInfo);
    }
  }

  /**
   * 将对象转换为URL参数字符串
   * @param {Object} obj - 要转换的对象
   * @returns {string} - 转换后的URL参数字符串
   */
  function objToParams(obj) {
    const params = new URLSearchParams();

    for (const key in obj) {
      // 处理数组类型的参数
      if (Array.isArray(obj[key])) {
        obj[key].forEach((value) => {
          params.append(key, value);
        });
      } else {
        params.append(key, obj[key]);
      }
    }

    return params.toString();
  }

  // --------------------------
  // 自定义处理函数示例
  // --------------------------

  /**
   * 保存artifacts信息到localStorage
   */
  function saveArtifactsToLocalStorage(responseData) {
    if (responseData && responseData.artifacts) {
      try {
        localStorage.setItem(
          "artifacts",
          JSON.stringify(responseData.artifacts)
        );
        console.log("[监听器] artifacts信息已保存到localStorage");
        return true;
      } catch (error) {
        console.error("[监听器] 保存artifacts到localStorage失败:", error);
        return false;
      }
    } else {
      console.warn("[监听器] 响应数据中未找到artifacts信息");
      return false;
    }
  }

  // 新增方法：获取资源下载链接
  function getResourceDownloadUrl(reqParams) {
    const url =
      "https://www.doubao.com/samantha/code/get_resource_download_url?" +
      objToParams(reqParams);

    const headers = {
      accept: "application/json, text/plain, */*",
      "accept-language": "zh-CN,zh;q=0.9",
      "agw-js-conv": "str",
      "content-type": "application/json",
      origin: "https://www.doubao.com",
      priority: "u=1, i",
      referer: window.location.href,
      "sec-ch-ua":
        '"Chromium";v="140", "Not=A?Brand";v="24", "Google Chrome";v="140"',
      "sec-ch-ua-mobile": "?0",
      "sec-ch-ua-platform": '"Windows"',
      "sec-fetch-dest": "empty",
      "sec-fetch-mode": "cors",
      "sec-fetch-site": "same-origin",
      "user-agent":
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36",
    };

    const body = {
      type: 3,
      artifacts_identifier: {
        code_id: "20378744161911554",
        code_version: 7,
        title: "wabi-sabi-startpage-3x3",
      },
    };

    fetch(url, {
      method: "POST",
      headers: headers,
      credentials: "include", // 携带当前页面的Cookie
      body: JSON.stringify(body),
    })
      .then((response) => response.json())
      .then((data) => console.log("获取下载链接结果:", data))
      .catch((error) => console.error("获取下载链接出错:", error));
  }

  // --------------------------
  // 监听fetch请求
  // --------------------------
  const originalFetch = window.fetch;
  window.fetch = async function (input, init) {
    try {
      // 获取请求URL
      const url = input instanceof Request ? input.url : input;
      const method = (init?.method || input.method || "GET").toUpperCase();

      // 发送请求并获取响应
      const response = await originalFetch(input, init);

      // 克隆响应以便多次读取
      const clonedResponse = response.clone();

      // 尝试解析响应内容
      let responseBody;
      try {
        const contentType = clonedResponse.headers.get("content-type");
        if (contentType && contentType.includes("application/json")) {
          responseBody = await clonedResponse.json();
        } else if (contentType && contentType.includes("text/")) {
          responseBody = await clonedResponse.text();
        } else {
          responseBody = `[二进制数据，长度: ${
            clonedResponse.headers.get("content-length") || "未知"
          }]`;
        }
      } catch (e) {
        responseBody = `[解析响应失败: ${e.message}]`;
      }

      // 构建请求信息对象
      const requestInfo = {
        type: "fetch",
        url: url,
        method: method,
        status: response.status,
        statusText: response.statusText,
        response: responseBody,
        timestamp: new Date().toISOString(),
      };

      // 处理请求信息
      processRequest(requestInfo);

      return response;
    } catch (error) {
      console.error("[监听器] fetch请求出错:", error);
      throw error;
    }
  };

  // --------------------------
  // 监听XMLHttpRequest请求
  // --------------------------
  const originalXHROpen = XMLHttpRequest.prototype.open;
  XMLHttpRequest.prototype.open = function (method, url) {
    // 保存请求信息
    this._requestMethod = method.toUpperCase();
    this._requestUrl = url;
    this._startTime = new Date().toISOString();

    // 监听请求完成事件
    this.addEventListener("load", function () {
      let responseBody;
      try {
        // 尝试解析JSON响应
        if (this.responseText) {
          responseBody = JSON.parse(this.responseText);
        } else {
          responseBody = null;
        }
      } catch (e) {
        // 解析失败则直接使用文本
        responseBody =
          this.responseText || `[无响应内容，状态: ${this.status}]`;
      }

      // 构建请求信息对象
      const requestInfo = {
        type: "XMLHttpRequest",
        url: this._requestUrl,
        method: this._requestMethod,
        status: this.status,
        statusText: this.statusText,
        response: responseBody,
        timestamp: this._startTime,
      };

      // 处理请求信息
      processRequest(requestInfo);
    });

    // 监听错误事件
    this.addEventListener("error", function () {
      console.error(
        `[监听器] XHR请求错误: ${this._requestMethod} ${this._requestUrl}`
      );
    });

    // 调用原始的open方法
    return originalXHROpen.apply(this, arguments);
  };

  console.log("[监听器] 增强版请求监听器已启动");
  console.log(
    "[监听器] 正在监听的URL规则:",
    config.watchRules.map((r) => r.urlContains)
  );
})();
